import requests
import os
import retry
from tqdm import tqdm
import chardet


class NetworkConnection:
    def __init__(self):
        # 初始化响应对象，用于存储请求的响应结果
        self.response = None

    @retry.retry(Exception, tries=3, delay=3, backoff=2)
    def connect(self, url, method=1, data=None):
        """
        连接到指定的网页，支持 GET 和 POST 请求
        :param url: 要连接的网页的 URL
        :param method: 请求方法，1 表示 GET，2 表示 POST，默认为 1
        :param data: POST 请求时要发送的数据
        :return: 网页的文本内容
        """
        if method == 1:
            # 发送 GET 请求
            self.response = requests.get(url)
        elif method == 2:
            # 发送 POST 请求
            self.response = requests.post(url, data=data)
        else:
            # 若请求方法不支持，抛出异常
            raise ValueError("不支持的请求方法，仅支持 1 (GET) 和 2 (POST)")
        # 自动检测编码
        detected_encoding = chardet.detect(self.response.content)['encoding']
        if detected_encoding:
            self.response.encoding = detected_encoding
        return self.response.text

    def get_status_code(self):
        """
        获取最后一次连接的网页的状态码
        :return: 网页的状态码
        """
        if self.response is None:
            # 若还未进行连接，抛出异常
            raise ValueError("还未进行连接，请先调用 connect 方法")
        # 返回响应的状态码
        return self.response.status_code

    def get_content(self):
        """
        获取最后一次连接的网页的内容
        :return: 网页的文本内容
        """
        if self.response is None:
            # 若还未进行连接，抛出异常
            raise ValueError("还未进行连接，请先调用 connect 方法")
        # 自动检测编码
        detected_encoding = chardet.detect(self.response.content)['encoding']
        if detected_encoding:
            self.response.encoding = detected_encoding
        return self.response.text

    @retry.retry(Exception, tries=3, delay=3, backoff=2)
    def download(self, url, save_path=None, mode=True):
        """
        下载指定网址的文件
        :param url: 要下载的文件的 URL
        :param save_path: 文件保存的路径，若为 None，则只读取不保存
        :param mode: 下载模式，True 表示显示进度条，False 表示不显示进度条
        :return: 若不保存文件，返回文件内容
        """
        try:
            # 发送流式 GET 请求
            response = requests.get(url, stream=True)
            # 检查请求是否成功，若不成功则抛出异常
            response.raise_for_status()

            # 获取文件的总大小
            total_size = int(response.headers.get('content-length', 0))
            # 每次读取的数据块大小
            block_size = 1024

            if save_path is not None:
                # 若指定了保存路径，将文件保存到本地
                with open(save_path, 'wb') as file:
                    if mode:
                        # 显示进度条
                        with tqdm(total=total_size, unit='iB', unit_scale=True) as pbar:
                            for data in response.iter_content(block_size):
                                # 更新进度条
                                pbar.update(len(data))
                                # 将数据写入文件
                                file.write(data)
                    else:
                        # 不显示进度条
                        for data in response.iter_content(block_size):
                            # 将数据写入文件
                            file.write(data)
            else:
                # 若不保存文件，将文件内容存储在变量中
                content = b""
                if mode:
                    # 显示进度条
                    with tqdm(total=total_size, unit='iB', unit_scale=True) as pbar:
                        for data in response.iter_content(block_size):
                            # 更新进度条
                            pbar.update(len(data))
                            # 累加数据
                            content += data
                else:
                    # 不显示进度条
                    for data in response.iter_content(block_size):
                        # 累加数据
                        content += data
                # 返回文件内容
                return True

        except requests.RequestException as e:
            # 处理请求异常
            print(f"下载过程中出现错误: {e}")
            return False

        except Exception as e:
            # 处理其他未知异常
            print(f"发生未知错误: {e}")
            return False

    # 用cookies下载
    @retry.retry(Exception, tries=3, delay=3, backoff=2)
    def download_file(self, url, save_path, cookies):
        # 将列表形式的 cookies 转换为字典形式
        cookie_dict = {cookie['name']: cookie['value'] for cookie in cookies}
        try:
            response = requests.get(url, cookies=cookie_dict, stream=True)
            response.raise_for_status()
            with open(save_path, 'wb') as file:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        file.write(chunk)
            # print(f"文件下载成功，保存路径: {save_path}")
            return True
        except requests.RequestException as e:
            # print(f"下载文件时出错: {e}")
            return False
